﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Threading;
using System.Xml.Linq;
using Core.ImageUtil;
using Core.Logger;

namespace Core
{
    /// <summary>
    /// Base class for managing the convertion from WP to BE.
    /// Xml and DB provider implementation should implement this class.
    /// </summary>
	public abstract class ProviderBase
	{
        /// <summary>
        /// The event is raised when images are downloaded. It is raised for
        /// every image downloaded. The event is raised only when 
        /// the <see cref="PostOption.DownloadImages"/> property is set to true.
        /// </summary>
        public EventHandler<DownloadingImagesArgs> DownloadingImageEvent;
        
        /// <summary>
        /// The event is raised when downloading images process is complete.
        /// </summary>
        public EventHandler<DownloadingImagesArgs> DownloadingImageComplete;

        private BackgroundWorker _worker;

        protected PostOption PostOption { get; set; }

	    /// <summary>
	    /// Gets or sets the post.
	    /// </summary>
        public Post Post { get; private set; }
        
        /// <summary>
        /// Gets or sets the post category.
        /// </summary>
	    public Category Category { get; private set; }

        /// <summary>
        /// Saves post categories.
        /// </summary>
        public abstract void SaveCategories();

        /// <summary>
        /// Saves posts.
        /// </summary>
        public abstract void SavePosts();

        /// <summary>
        /// Saves post pages.
        /// </summary>
        public abstract void SavePages();

        /// <summary>
        /// Parses the WP Xml file and builds the BE object.
        /// </summary>
        /// <param name="fileName"></param>
        public void Parse(string fileName)
        {
            try
            {
                XElement xElement = XElement.Load(fileName);
                this.Post = new Post(this.PostOption);
                Post.Parse(xElement);
            }
            catch (Exception ex)
            {
                LoggerInstance.Append(LogStatus.Error, "Error parsing the file: {0}", ex.Message);
            }
        }

        /// <summary>
        /// Processes the post object creating all the dependencies, changing image location tags
        /// and preparing the Post to be saved.
        /// </summary>
        public void Process()
        {
            this.Post.Process();
        }

        /// <summary>
        /// Saves the blog post including categories and pages.
        /// </summary>
        public void Save()
        {
            this.SaveCategories();
            this.SavePosts();
            this.SavePages();

            if (this.PostOption.DownloadImages)
            {
                this.DownloadImagesBackground();
            }
        }

        private void DownloadImagesBackground()
        {
            _worker = new BackgroundWorker();
            _worker.WorkerSupportsCancellation = true;
            _worker.DoWork += worker_DoWork;
            _worker.RunWorkerCompleted += worker_RunWorkerCompleted;
           _worker.RunWorkerAsync();
   
        }

	    private void worker_DoWork(object sender, DoWorkEventArgs e)
	    {
            foreach (PostImage postImage in this.Post.PostImages)
            {
                if (_worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
                // Save Href image (when click on image it goes to href)
                this.SaveImage(postImage.Href, postImage.HrefFileName, false);
                // Save Image (the image which is displayed on the post - thumbnail pict)
                this.SaveImage(postImage.ImgSrc, postImage.ImgSrcFileName, true);
            }
        }

        private void SaveImage(string url, string fileName, bool thumbnail)
        {
            Image image = null;
            try
            {
                if (!Directory.Exists(this.PostOption.LocalImageFolder))
                {
                    Directory.CreateDirectory(this.PostOption.LocalImageFolder);
                }

                OnDownloadingImage(new DownloadingImagesArgs(fileName));
                
                WebClient wb = new WebClient();
                
                image = Image.FromStream(wb.OpenRead(url));
                string destFileName = Path.Combine(this.PostOption.LocalImageFolder, fileName);
                
                if (this.PostOption.AddImgDropShadow && thumbnail)
                {
                    ImageDropShadow.Draw(image, destFileName);
                }
                else
                {
                    image.Save(destFileName);
                }

            }
            catch (Exception ex)
            {
                System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    (ThreadStart) delegate()
                    {
                        LoggerInstance.Append(LogStatus.Error, "Error downloading image: {0} To {1} : {2}", url, fileName, ex.Message);
                    });
            }
            finally
            {
                if (image != null) image.Dispose();
            }
        }

        public void CancelDownloadImages()
        {
            if (_worker == null) return;
            
            if (_worker.IsBusy)
            {
                _worker.CancelAsync();
            }
        }

        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            DownloadingImagesArgs imgArgs;
            if (e.Cancelled)
            {
                imgArgs = new DownloadingImagesArgs(DownloadImagesComplete.Canceled);
            }
            else
            {
                imgArgs = new DownloadingImagesArgs(DownloadImagesComplete.Successfully);
            }

	        OnDownloadingImageComplete(imgArgs);
	    }

	    private void OnDownloadingImage(DownloadingImagesArgs e)
	    {
	        var temp = DownloadingImageEvent;
            if (temp != null)
            {
                DownloadingImageEvent(this, e);
            }
	    }

        private void OnDownloadingImageComplete(DownloadingImagesArgs e)
        {
            var temp = DownloadingImageComplete;
            if (temp != null)
            {
                temp(this, e);
            }
        }
	}
} 